package com.uab.ia.utils;

import java.util.ArrayList;

import android.os.AsyncTask;
import android.util.Log;

import com.uab.ia.entidades.Camino;
import com.uab.ia.entidades.Node;

public class AEstrella extends AsyncTask<Long, Void, Camino> {

	/*
	 * Aqui declara les variables:
	 * 
	 * private ArrayCaminos openset; private ArrayCaminos closedset; private
	 * Camino current; ....
	 */
	boolean enc;
	private long start;
	private long end;
	private OnAEstrellaListener listener;
	private Utils utils;
	private Camino open;
	private ArrayList<Long> closed;
	private double maximoCoste;

	@Override
	protected Camino doInBackground(Long... params) {

		start = params[0];
		end = params[1];

		Double acumulado = 0.0;
		boolean auxTrobat=false;

		utils = Utils.getInstance();
		Node mejor = new Node(start);

		open = new Camino();
		closed = new ArrayList<Long>();
		mejor.setCostG(utils.getEstimatedHeuristic(start, end));
		mejor.setCostA(0.0);
		open.add(mejor);
		mejor = buscarMejor();

		

		if (start == end) {
			Camino c = new Camino();
			c.add(new Node(start));
			c.add(new Node(end));
			return c;
		}

		while (!open.isEmpty()) {
			
			maximoCoste = utils.getTimeAndandoBetweenEstaciones(mejor.id, end);

			enc = inTheEnd(mejor.id, end);
			boolean buenRollo = false;
			
			Log.i("tag", "ID MEJOR: " + mejor.id+ " END: "+ end);

			if (enc) {
				for (Node node : open) {
					if (node.getCosteT() < mejor.getCosteT()) {
						buenRollo = true;
					}
				}

				if (!buenRollo) {
					Camino c = new Camino();
					c.add(mejor);
					c.setCosteA(mejor.getCostA());
					c.setCosteH(mejor.getCostG());
					c.creado = true;
					Log.i("tag", "devolvemos por aqui");
					return c;
				}
			}

			acumulado = mejor.getCostA();
			auxTrobat = false;
			for (long desti = 1; desti <= 39; desti++) {
				if (desti != mejor.id) {
					Node newNode = new Node(desti);
					newNode.setCostA(acumulado
							+ utils.getTimeBetweenEstaciones(mejor.id,
									newNode.id));
					newNode.setCostG(utils.getEstimatedHeuristic(newNode.id,
							end));
					
					if (newNode.getCostG() <= maximoCoste && !closed.contains(desti)) {
						newNode.setParentId(mejor.id);
						newNode.setParent(mejor);
							open.add(newNode);
							auxTrobat = true;
					}

				}
			}
			if (!auxTrobat){
				Node nodofinal; 
				nodofinal = buscarID(end);
				Camino c = new Camino();
				c.add(nodofinal);
				c.setCosteA(nodofinal.getCostA());
				c.setCosteH(nodofinal.getCostG());
				c.creado = true;
				Log.i("tag", "entra aqui");
				return c;
			}
			if (mejor.id !=end){
				closed.add(mejor.id);
			}
			if(mejor.id!=end){
				open.remove(mejor);
			}
			
			mejor = buscarMejor();
			Log.i("tag", "ID expandimos " + mejor.id);

		}

		return null;
	}

	private Node buscarID(long id) {
		Double basico = 99999.9;
		Node nodeReturn=null;
		for (Node node : open) {
			if (node.id == id) {
				if (node.getCosteT()<basico){
					basico = node.getCosteT();
					nodeReturn = node;
				}
			}
		}
				return nodeReturn;
	}

	private Node buscarMejor() {
		Double basico = open.get(0).getCosteT();
		Node nodeReturn = open.get(0);
		for (Node node : open) {
			if (node.getCosteT() < basico) {
				if(!closed.contains(node.id)){
					basico = node.getCosteT();
					nodeReturn = node;
				}
			}
		}
		return nodeReturn;
	}

	private boolean inTheEnd(long idNodeMejor, long idEND) {
		if (idNodeMejor == idEND) {
			return true;
		}
		return false;
	}

	@Override
	protected void onPostExecute(Camino camino) {
		super.onPostExecute(camino);
		if (listener != null) {
			if (camino != null) {
				listener.OnCaminoEncontrado(camino, start, end);
			} else {
				listener.OnNoHayCamino(start, end);
			}
		}
	}

	public OnAEstrellaListener getListener() {
		return listener;
	}

	public void setListener(OnAEstrellaListener listener) {
		this.listener = listener;
	}

	public interface OnAEstrellaListener {
		void OnCaminoEncontrado(Camino c, long start, long end);

		void OnNoHayCamino(long start, long end);
	}
}
